package com.example.code.juc;


import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

class Mydata {
    volatile int number = 0;

    void modifyData() {
        this.number = 60;
    }

    // number是volatile修饰的，volatile不保证原子性
    void addPlusPlus() {
        number++;
    }

    AtomicInteger atomicInteger = new AtomicInteger();

    void addAtomic() {
        atomicInteger.incrementAndGet();
    }
}

/**
 * 1.验证volatile的可见性
 *      1.1 假如 int number = 0;number变量根本没有添加volatile关键字修饰，没有可见性
 *      1.2 添加了volatile，可以解决可见性问题
 *
 * 2.验证volatile不保证可见性
 *      2.1 原子性是什么意思呢？
 *          不可分割，完整性，也即某个线程正在做某个具体业务时，中间不可以被加塞或者被分割，需要整体完整
 *          要么同时成功，要么同时失败
 *
 *      2.2 volatile不保证原子性示例演示 见main方法中的number结果打印值
 *
 *      2.3 why
 *
 *      2.4 如何解决原子性？
 *          ~ 加synchronized关键字
 *          ~ 用AtomicInteger原子类操作
 */
class VolatileDemo {
    public static void main(String[] args) {
        Mydata mydata = new Mydata();

        for (int i = 1; i <= 20; i++) {
            new Thread(() -> {
                for (int j = 0; j < 1000; j++) {
                    mydata.addPlusPlus();

                    mydata.addAtomic();
                }
            }, String.valueOf(i)).start();
        }
        // 等待以上20个线程全部计算完成之后，再用main线程看number的值
        while (Thread.activeCount() > 2) {
            Thread.yield();
        }

        System.out.println("int 最终结果值：" + mydata.number);
        System.out.println("Atomic 最终结果值：" + mydata.atomicInteger);
    }

    /**
     * volatile可以保证可见性，及时通知其他线程，主内存中的变量已经修改
     */
    public static void seeOkByVolatile() {
        Mydata mydata = new Mydata();
        new Thread(() -> {
            System.out.println(Thread.currentThread() + "进来了");
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            mydata.modifyData();
            System.out.println(Thread.currentThread() + "修改了值" + mydata.number);
        }, "线程A").start();

        while (mydata.number == 0) {
            // main线程一直在循环等待，直到number呗修改不为0才结束循环
        }
        System.out.println(Thread.currentThread() + "执行结束");
    }
}
